//
//  SEChatTextParser.swift
//  SmartEyeForPatient
//
//  Created by QDSG on 2021/4/9.
//

import Foundation
import YYText

public let kChatTextKeyPhone = "phone"
public let kChatTextKeyURL = "URL"

class SEChatTextParser: NSObject {
    static func parseText(_ text: String, font: UIFont, image: UIImage?, fromMe: Bool) -> NSMutableAttributedString? {
        if text.count == 0 { return nil }

        let attributedText = NSMutableAttributedString(string: text)
        attributedText.yy_font = font
        attributedText.yy_color = .black

        enumeratePhoneParser(attributedText)
        enumerateURLParser(attributedText)

        guard let image = image else { return attributedText }

        let height: CGFloat = 14.0
        let width = (image.size.width) * height / (image.size.height) + 8.0
        let index = fromMe ? text.count : 0
        let contentMode: UIView.ContentMode = fromMe ? .right : .left

        let attachString = NSMutableAttributedString.yy_attachmentString(
            withContent: image,
            contentMode: contentMode,
            attachmentSize: CGSize(width: width,
                                   height: height),
            alignTo: font,
            alignment: .center)
        attributedText.insert(attachString, at: index)

        return attributedText
    }
    
    /// 匹配 电话
    private static func enumeratePhoneParser(_ attributedText: NSMutableAttributedString) {
        let phonesResults = SEChatTextParseHelper.regexPhoneNumber.matches(
            in: attributedText.string,
            options: [.reportProgress],
            range: attributedText.yy_rangeOfAll()
        )
        
        for phone in phonesResults {
            if phone.range.location == NSNotFound && phone.range.length <= 1 {
                continue
            }
            
            let highlightBorder = SEChatTextParseHelper.highlightBorder
            if attributedText.yy_attribute(YYTextHighlightAttributeName, at: UInt(phone.range.location)) == nil {
                attributedText.yy_setColor(Asset.chatTextHightlight.color, range: phone.range)
                let highlight = YYTextHighlight()
                highlight.setBackgroundBorder(highlightBorder)
                
                if let stringRange = attributedText.string.range(from: phone.range) {
                    highlight.userInfo = [kChatTextKeyPhone: String(attributedText.string[stringRange])]
                    attributedText.yy_setTextHighlight(highlight, range: phone.range)
                }
            }
        }
    }
    
    /// 匹配 URL
    private static func enumerateURLParser(_ attributedText: NSMutableAttributedString) {
        let URLsResults = SEChatTextParseHelper.regexURLs.matches(
            in: attributedText.string,
            options: [.reportProgress],
            range: attributedText.yy_rangeOfAll()
        )
        for url in URLsResults {
            if url.range.location == NSNotFound && url.range.length <= 1 {
                continue
            }
            
            let highlightBorder = SEChatTextParseHelper.highlightBorder
            if attributedText.yy_attribute(YYTextHighlightAttributeName, at: UInt(url.range.location)) == nil {
                attributedText.yy_setColor(Asset.chatTextHightlight.color, range: url.range)
                let highlight = YYTextHighlight()
                highlight.setBackgroundBorder(highlightBorder)
                
                if let stringRange = attributedText.string.range(from: url.range) {
                    highlight.userInfo = [kChatTextKeyURL: String(attributedText.string[stringRange])]
                    attributedText.yy_setTextHighlight(highlight, range: url.range)
                }
            }
        }
    }
}

class SEChatTextParseHelper {
    /// 高亮的文字背景色
    static var highlightBorder: YYTextBorder {
        get {
            let highlightBorder = YYTextBorder()
            highlightBorder.insets = UIEdgeInsets.init(top: -2, left: 0, bottom: -2, right: 0)
            highlightBorder.fillColor = UIColor(hex: "#D4D1D1")
            return highlightBorder
        }
    }
    
    
    /**
     正则：匹配 [哈哈] [笑哭。。] 表情
     */
    static var regexEmotions: NSRegularExpression {
        get {
            let regularExpression = try! NSRegularExpression(pattern: "\\[[^\\[\\]]+?\\]", options: [.caseInsensitive])
            return regularExpression
        }
    }
    
    /**
     正则：匹配 www.a.com 或者 http://www.a.com 的类型
     
     ref: http://stackoverflow.com/questions/3809401/what-is-a-good-regular-expression-to-match-a-url
     */
    static var regexURLs: NSRegularExpression {
        get {
            let regex: String = "((http[s]{0,1}|ftp)://[a-zA-Z0-9\\.\\-]+\\.([a-zA-Z]{2,4})(:\\d+)?(/[a-zA-Z0-9\\.\\-~!@#$%^&*+?:_/=<>]*)?)|^[a-zA-Z0-9]+(\\.[a-zA-Z0-9]+)+([-A-Z0-9a-z_\\$\\.\\+!\\*\\(\\)/,:;@&=\\?~#%]*)*"
            let regularExpression = try! NSRegularExpression(pattern: regex, options: [.caseInsensitive])
            return regularExpression
        }
    }
    
    /**
     正则：匹配 7-25 位的数字, 010-62104321, 0373-5957800, 010-62104321-230
     */
    static var regexPhoneNumber: NSRegularExpression {
        get {
            let regex = "([\\d]{7,25}(?!\\d))|((\\d{3,4})-(\\d{7,8}))|((\\d{3,4})-(\\d{7,8})-(\\d{1,4}))"
            let regularExpression = try! NSRegularExpression(pattern: regex, options: [.caseInsensitive])
            return regularExpression
        }
    }
}

private extension String {
    func nsRange(from range: Range<String.Index>) -> NSRange {
        let utf16view = self.utf16
        if let from = range.lowerBound.samePosition(in: utf16view),
           let to = range.upperBound.samePosition(in: utf16view) {
            return NSMakeRange(utf16view.distance(from: utf16view.startIndex, to: from),
                               utf16view.distance(from: from, to: to))
        } else {
            return NSMakeRange(0, 0)
        }
    
    }
    
    func range(from nsRange: NSRange) -> Range<String.Index>? {
        guard let from16 = utf16.index(utf16.startIndex, offsetBy: nsRange.location, limitedBy: utf16.endIndex),
              let to16 = utf16.index(from16, offsetBy: nsRange.length, limitedBy: utf16.endIndex),
              let from = String.Index(from16, within: self),
              let to = String.Index(to16, within: self) else { return nil }
        return from ..< to
    }
}
